﻿using System;
using System.Collections;
using System.IO;
//using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace SerialCapture
{
    class KPITraceAnalyzer
    {   /// this class is the abstract object for the trace analyze special for Geely. 
        /// generally when the serial obj get traces from the serial port. normally it is a line.
        /// this line will be send to KPITraceAnalyzer, and KPITraceAnalyzer is responsilbe for 
        /// a. filter out key of the KPI state.
        /// b. record the time of the KPI state and calculate the KPI.
        /// c. log the KPI to KPI log file.
        /// 
        //public DictionaryEntry tmpKPI = new DictionaryEntry();
        private ArrayList myKPIKeys = new ArrayList();
        //private Boolean KPIFinished;
        private int KPICount;
        private Log myKPILog;
        //private FileInfo logKPI;
        
        
        private ArrayList myKPIResults = new ArrayList();
        private long startupTime;
        private double timeBase;
        private string timeUnit;

        public KPITraceAnalyzer() {
            //this.myKPIKeys = new ArrayList();
            this.timeBase = 10000000.00;
            this.timeUnit = "[seconds]";
            myKPILog = new Log();
        }

        //private ArrayList KPIKeys;
        //when the trace is received from objSerial, call this function for the analyze
        // if trace here contain newLine indicator, the method should split the trace automatically.
        //para in: strTrace string

        public Boolean analyzeTrace(string strTrace) {
            Boolean returnResult;
            returnResult = false;
            if (KPIPreAnalyze(strTrace))//&& this.KPICount > 0
            {
                //                
                foreach (string keys in myKPIKeys)
                {
                    //if (keys == "BootAnimationShow") {
                    //    string t = "tt";
                    //}
                    if (analyzeStartUp(strTrace))
                    {
                        returnResult = true;
                        break;
                    }
                    else {
                        if (analyzeService(strTrace, keys) || analyzeOther(strTrace, keys))
                        {
                            returnResult = true;
                            break;
                        }
                        else
                        {
                            if (analyzeDevState(strTrace))
                            {
                                returnResult = true;
                                break;
                            }
                        }
                    }
                }
                return returnResult;
            }
            else {
                //this is not KPI trace.
                return returnResult;
            }
        }

        public Boolean analyzeCamera(string trace){
            return true;
        }

        #region Private Declaed Function
        //for the performance concern, we only parse some of the traces.
        //contain below words then we parse.
        private Boolean KPIPreAnalyze(string trace) {
            if (    trace.Contains("at time")
                 || trace.Contains("deviceState") 
                 || trace.Contains("result:") 
                 || trace.Contains("Boot from flash") 
                 || trace.Contains("warning dialog")
                 || trace.Contains("bootAnimation")
                 || trace.Contains("Sync system time"))
            {
                if(trace.Contains("Boot from flash")){
                    this.initMyKPIKeys();
                }
                
                return true;
            }
            else {
                return false;
            }
        }

        private Boolean analyzeStartUp(string trace) {
            Boolean outResult;
            string s;
            outResult = false;

            DictionaryEntry tmpKPI = new DictionaryEntry();

            if (trace.Contains("Boot from"))
            {
                tmpKPI.Key = "Startup";
                tmpKPI.Value = 0;
                outResult = true;
                //add this function for saving time concern
                myKPIKeys.Remove(tmpKPI.Key);
                //s = "Detected Startup";
                //myKPILog.appendLogText(DateTime.Now.Ticks.ToString(),logFileTypeEnum.KPI );
                //myKPILog.appendLogText("");
                //this.startupTime = DateTime.Now.Ticks;
                if (this.myKPIResults.Count > 0)
                {
                    //before clear the old result. we need to record the result to a log file.
                    foreach (DictionaryEntry KPIDic in this.myKPIResults)
                    {
                        myKPILog.appendLogText(KPIDic.Key.ToString() + " " + ((double)KPIDic.Value).ToString(".00") + this.timeUnit + " after startup.", logFileTypeEnum.KPI);
                    }
                    this.myKPIResults.Clear();
                }
                else { 
                
                }
                myKPILog.appendLogText("", logFileTypeEnum.KPI);
                myKPILog.appendLogText("==================================I am the Spliter==================================",logFileTypeEnum.KPI);
                myKPILog.appendLogText("================================I am the Spliter again==============================",logFileTypeEnum.KPI);
                myKPILog.appendLogText("", logFileTypeEnum.KPI);
                myKPILog.appendLogText("Startup Detected.", logFileTypeEnum.KPI);
                this.startupTime = DateTime.Now.Ticks;
                //myKPILog.appendLogText(DateTime.Now.Ticks.ToString(),logFileTypeEnum.KPI);
            }
            else {
                //myKPILog.appendLogText(trace, logFileTypeEnum.KPI);
            }
            return outResult;
        }

        private Boolean analyzeDevState(string trace) { 
            //this one need to handle not only the ready state. but also the playable state.
            //first we need to cut out all the strings after the devState]
            //Regex devStateRex = new Regex();
            //Regex.ma
            //string outResult;
            string deviceType;
            Boolean myOutResult;
            Regex regAvailable = new Regex("\"available\":true");
            Regex regContent = new Regex("\"content\":\"[^0-9]+\"");
            Regex regType = new Regex("\"type\":\"[a-z]+\"");

            deviceType = "unknown device";
           // outResult = null;
            myOutResult = false;
            if (regAvailable.IsMatch(trace))
            {
                //myKPILog.appendLogText("find devState: " + trace, logFileTypeEnum.KPI);
                myOutResult = true;
                if (regType.IsMatch(trace))
                {
                    foreach (Match mar in regType.Matches(trace))
                    {
                        deviceType = mar.Groups[0].Value.Replace("\"", "").Split(':')[1];
                    }
                }
                DictionaryEntry tmpDic = new DictionaryEntry();
                tmpDic.Key = deviceType + " Detected";
                tmpDic.Value = (DateTime.Now.Ticks - this.startupTime) / timeBase;

                if (regContent.IsMatch(trace))
                {
                    tmpDic.Key = deviceType + " Playable";
                    tmpDic.Value = (DateTime.Now.Ticks - this.startupTime) / timeBase;
                }
                addKPIResult(tmpDic);
                //myKPILog.appendLogText("add key: " + tmpDic.Key.ToString() + "add value: " + ((double)tmpDic.Value).ToString(".00"),logFileTypeEnum.KPI); 
            }
            return myOutResult;
        }

        private void addKPIResult(DictionaryEntry resultDic) {
            this.myKPIResults.Add(resultDic);
            this.KPICount -= 1;
            if (this.KPICount == 0) {
                this.initMyKPIKeys();
            }
        }

        private Boolean analyzeService(string trace, string keywords) {
            DictionaryEntry tmpKPI = new DictionaryEntry();

            if (trace.Contains("com.harman.service." + keywords))
            {
                tmpKPI.Key = keywords;
                tmpKPI.Value = (DateTime.Now.Ticks - this.startupTime) / timeBase;
                //this.myKPIResults.Add(tmpKPI);
                addKPIResult(tmpKPI);
                myKPIKeys.Remove(tmpKPI.Key);
                return true;
            }
            else {
                return false;
            }
        }

        private Boolean analyzeOther(string trace, string keywords) {
            DictionaryEntry tmpKPI = new DictionaryEntry();
            if (trace.Contains(keywords))
            {
                tmpKPI.Key = keywords;
                tmpKPI.Value = (DateTime.Now.Ticks - this.startupTime) / timeBase;
                //this.myKPIResults.Add(tmpKPI);
                addKPIResult(tmpKPI);
                myKPIKeys.Remove(tmpKPI.Key);
                return true;
            }
            else {
                return false;
            }
        
        }

        private void initMyKPIKeys() {
            myKPIKeys.Add("StartUp");
            myKPIKeys.Add("bootAnimation start");
            myKPIKeys.Add("SystemInfoTouchCalib");
            myKPIKeys.Add("Tuner");
            myKPIKeys.Add("AudioCtrlSvc");
            myKPIKeys.Add("BluetoothService");
            myKPIKeys.Add("warning dialog shows");
            myKPIKeys.Add("Media");
            myKPIKeys.Add("USB");
            myKPIKeys.Add("SD");
            myKPIKeys.Add("BT");
            myKPIKeys.Add("iPod");
            myKPIKeys.Add("Sync system time");
            myKPIKeys.Add("Navigation");

            //once you add new KPI key. please also update this.KPICount and analyze function.
            this.KPICount = 16 + 3;
        }
        #endregion
    }
}
